﻿using huqiang;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class LuaBundle
{
    struct KeyData
    {
        public string Key;
        public string Lower;
        public byte[] Data;
    }
    public string name;
    public string version;
    List<KeyValue> values;
    List<KeyData> datas;
    public bool Clip;
    public string clipHead = "--debug";
    public string clipEnd = "--end";
    public void Add(string name, string path)
    {
        if (values == null)
            values = new List<KeyValue>();
        string key = name.Replace('\\', '/').ToLower();
        values.Add(new KeyValue() {
            key= key,
            value = path}
        );
    }
    public void Write(string path)
    {
        if (File.Exists(path))
            File.Delete(path);
        var fs = File.Create(path);
        fs.Write(values.Count.ToBytes(), 0, 4);
        StringBuilder sb = new StringBuilder();
        
        for(int i=0;i<values.Count;i++)
        {
            string fp = values[i].value;
            byte[] key = Encoding.UTF8.GetBytes(values[i].key);
            fs.Write(key.Length.ToBytes(), 0, 4);
            fs.Write(key, 0, key.Length);
            if(Clip)
            {
                sb.Clear();
                string lua = File.ReadAllText(fp);
                lua = lua.Replace("\r\n","\n");
                string[] ss = lua.Split('\n');
                bool cut = false;
                for (int j = 0; j < ss.Length; j++)
                {
                    string str = ss[j].TrimStart();
                    if(str.IndexOf(clipHead)==0)
                    {
                        cut = true;
                    }else if(str.IndexOf(clipEnd)==0)
                    {
                        cut = false;
                    }
                    else if(!cut)
                    {
                        sb.Append(str);
                        sb.Append('\n');
                    }
                }
                var dat = Encoding.UTF8.GetBytes(sb.ToString());
                fs.Write(dat.Length.ToBytes(), 0, 4);
                fs.Write(dat, 0, dat.Length);
                if(cut)
                {
                    UnityEngine.Debug.LogError("未能找到裁剪标记的结束标识符:"+ values[i].key);
                }
            }
            else
            {
                var dat = File.ReadAllBytes(fp);
                fs.Write(dat.Length.ToBytes(), 0, 4);
                fs.Write(dat, 0, dat.Length);
            }
        }
        fs.Dispose();
    }
    public void Read(string path)
    {
        Read(File.ReadAllBytes(path));
    }
    public void LoadFromAbb(string path)
    {
        var ab = UnityEngine.AssetBundle.LoadFromFile(path);
        var ta = ab.LoadAsset<UnityEngine.TextAsset>("abb.bytes");
        Read(ta.bytes);
        ab.Unload(true);
    }
    public void Read(byte[] data)
    {
        datas = new List<KeyData>();
        int len = data.ReadInt32(0);
        int offset = 4;
        for(int i=0;i<len;i++)
        {
            var kd = new KeyData();
            int l = data.ReadInt32(offset);
            offset += 4;
            if (l > 0)
            {
                kd.Key = Encoding.UTF8.GetString(data, offset, l);
            }
            offset += l;
            l = data.ReadInt32(offset);
            offset += 4;
            if(l>0)
            {
                byte[] dat = new byte[l];
                Array.Copy(data, offset, dat, 0, l);
                kd.Data = dat;
            }
            offset += l;
            kd.Lower = kd.Key.Replace('\\', '/').ToLower();
            datas.Add(kd);
        }
    }
    public byte[] Find(string name)
    {
        if (name.IndexOf("Assets")==0)
        {
            UnityEngine.Debug.LogError("引用名称错误:"+ name);
            name = name.Replace("Assets/Code/ToLua/Lua/","");
        }
        if (!name.Contains(".lua"))
            name = name + ".lua";
        name = name.ToLower();
        for (int i = 0; i < datas.Count; i++)
            if (datas[i].Lower == name)
                return datas[i].Data;
        UnityEngine.Debug.LogError("未能找到文件:" + name);
        return null;
    }
    /// <summary>
    /// 将数据写入到文件
    /// </summary>
    /// <param name="folder"></param>
    public void WriteFiles(string folder)
    {
        if (datas == null)
            return;
        for (int i = 0; i < datas.Count; i++)
        {
            CheckDic(folder,datas[i].Key);
            string fp = folder + "/" + datas[i].Key;
            if(datas[i].Data!=null)
            {
                if (datas[i].Data.Length > 0)
                {
                    File.WriteAllBytes(fp, datas[i].Data);
                }
                else
                {
                    if (File.Exists(fp))
                        File.Delete(fp);
                    File.Create(fp).Close();
                }
            }
            else
            {
                if (File.Exists(fp))
                    File.Delete(fp);
                File.Create(fp).Close();
            }
        }
    }
    /// <summary>
    /// 开启一个线程，将数据写入到文件
    /// </summary>
    /// <param name="folder"></param>
    public void WriteFilesAsync(string folder)
    {
        Task.Run(()=> {
            WriteFiles(folder);
        });
    }
    void CheckDic(string folder,string filename)
    {
        string[] ss = filename.Split('/');
        if (ss.Length > 1)
        {
            string dic = folder;
            for (int i = 0; i < ss.Length - 1; i++)
            {
                dic = dic + "/" + ss[i];
                if (!Directory.Exists(dic))
                {
                    Directory.CreateDirectory(dic);
                }
            }
        }
    }

    public void WriteText(string path)
    {
        StringBuilder builder = new StringBuilder();
        for(int i=0;i< values.Count;i++)
        {
            var kd = values[i];
            builder.Append(kd.key);
            builder.Append('\n');
            builder.Append(File.ReadAllText(kd.value));
            builder.Append('\n');
        }
        File.WriteAllText(path,builder.ToString());
    }
}
